fix(daemon): Cancel timed-out session initialization - #10268
Conversation
E2E test reportVerified on rebased commit
The complete built-daemon scenario could not run because |
|
Gate re-pass on head Template: complete ✓ (re-checked against the current template) Problem: unchanged and real — an observed bug, not hardening. The public Direction: aligned. This closes a genuine daemon correctness hole while keeping the public Size: recomputed from the files API this run: 774 production logic lines (bridge.ts 547, acpAgent.ts 75, client.ts 40, bridgeErrors.ts 36, config.ts 29, dispatch.ts 23, error-response.ts 13, smaller files 11) vs 1320 test lines vs 97 docs lines. Core + cross-package ( Approach: scope remains justified rather than bloated. Child-side cancellation alone cannot cover older children that ignore the deadline, so the bridge's late-settlement containment (exact-ID close, fences, bounded quarantine that spares healthy siblings) is part of the stated goal, not scope creep. @wenshao's verification raised four non-blocking notes (N1–N4); the author deferred them under the review-round churn rule, which is the right call past the fifth round — none is a Critical. Risk: Stage 1e matches 中文说明在 head 模板: 完整 ✓(已按当前模板重新核对) 问题: 不变且真实 —— 已观测到的 bug,不是理论加固。公开的 方向: 对齐。修补真实的 daemon 正确性漏洞,同时保持公开 规模: 本轮经 files API 重新计算:774 行生产逻辑(bridge.ts 547、acpAgent.ts 75、client.ts 40、bridgeErrors.ts 36、config.ts 29、dispatch.ts 23、error-response.ts 13、其余小文件 11),测试 1320 行,文档 97 行。核心 + 跨包( 方案: 范围仍然合理而非膨胀。仅靠子进程侧取消无法覆盖忽略 deadline 的旧子进程,因此 Bridge 的迟到 settle 约束(精确 ID 关闭、fence、不伤及健康兄弟的有界隔离)是目标的一部分,不是夹带。@wenshao 的验证提出四条非阻断注记(N1–N4),作者按评审轮次 churn 规则延后处理 —— 在已超过五轮的 PR 上这是正确做法;均非 Critical。 风险: Stage 1e 命中 — Qwen Code · qwen3.8-max Reviewed at |
Code review — round 5 (head
|
| Check | Conclusion |
|---|---|
| Test (ubuntu-latest, Node 22.x) | success |
| Integration Tests (no-AK, No Sandbox) | success |
| Serve A/B (ubuntu-latest, Node 22.x) | success |
| Real daemon E2E / Java 11 | success |
| Desktop Shell (ubuntu-22.04) · Desktop Shell (windows-2022) | success |
| web-shell E2E Smoke (ubuntu-latest, Node 22.x) | success |
| SDK Java (ubuntu 11/17/21, macos 21, windows 21) | success |
| Dependency CVE audit · Secret scan (TruffleHog) | success |
| precheck-pr / precheck | success |
| Integration Tests (CLI, No Sandbox) | skipped (fork gating) |
| Test (macos-latest, Node 22.x) · Test (windows-latest, Node 22.x) | skipped (fork gating) |
The central claim is behavioural and the green unit suite alone does not pin it — the bridge tests exercise fake channels. Two lanes that can settle it have now both landed on this head:
- The sandboxed
@qwen-code /verifyrun reported ✅ passed — merge-ready (agent verdict) (run 33241428739): A/B against the base build, mock-free harness assertions, targeted gates. It is advisory evidence for human reviewers — still the product of an automated pipeline, so read it as one input, not a verdict. - @wenshao independently ran the full Reviewer Test Plan against a real
qwen servedaemon with realqwen --acpchildren on Linux (three arms: base vs PR head) and reported that everything the PR claims reproduces — timed-out init reaps the hook process tree, an older child settling late is closed by exact ID, cleanup-uncertainty fails closed for fresh admission only, and the healthy sibling stays usable. That is maintainer evidence, not mine, and it is the strongest signal in this thread. His four non-blocking notes (N1–N4) were reviewed by the author and deferred under the churn rule.
Nothing behavioural about this PR rests on the author's word alone anymore.
中文说明
代码审查 —— 第 5 轮(head 93c909cede,无变化)
自第 4 轮审查以来没有新代码落地 —— 本轮针对同一 SHA,第 4 轮的结论继续有效。我没有仅凭信任复述,而是在本轮重新对照该 head 的代码核验了第 6 轮四个 Critical 的修复:
第 6 轮 Critical —— 在该 head 上仍均可验证地修复:
- R6-1(init_timeout 映射): 两个传输层都把 504
init_timeout契约限定在newSessionlabel 上 ——sendBridgeError(error-response.ts:217)与toRpcError(dispatch.ts:843),其余超时 label 走通用内部错误路径。顺序风险仍被正确处理:两个传输层都先匹配子类SessionRestoreTimeoutError(error-response.ts:200;dispatch.ts:824),restore 超时不会被重映射为init_timeout。测试同时钉住了映射与通用回退。 - R6-2(restore close 被拒): 被弃 restore 清理与 newSession 路径一致地要求
closeResult['closed'] === true(bridge.ts:7498),被拒时隔离 channel(restore_cleanup_failed,bridge.ts:7536),resource-not-found 与传输关闭按已结算状态处理。 - R6-3(InstructionsLoaded 信号): 初始化信号经
refreshHierarchicalMemory('session_start', options?.signal)(config.ts:3473)传入createInstructionsLoadedCallback(() => this.hookSystem, signal)(config.ts:3967)。第 7 轮跟进注记(回调本身无法暴露取消)仍为建议级延后项,不是 Critical。 - R6-4(overdue 标志从不清除): channel 级的
restoreSettlementOverdue布尔已移除 —— grep 零匹配。freshSessionBlocker()(bridge.ts:2641)扫描按 id 的overdueAbandonedRestores/overdueAbandonedNewSessions集合,外加newSessionCleanupFailed与isQuarantined,唯一的 overdue restore 结算后准入即刻重开。
可信路径门控保持可靠。 acpAgent.ts 中的 deadline 处理一致地被 isTrustedManagedParent() 围栏(11 处调用);不可信父进程的 deadline 被忽略。
本轮无新发现 —— 同一 head、同一代码。其余为第 7 轮已记录在案的非阻断项(六条此前报告并延后的建议级发现,主要是 R5-1 —— 504 契约只在 mapper 单测层钉住,缺路由级测试 —— 外加两条探针级小项)。以我的判断均不构成合并门槛。@wenshao 的四条验证注记(N1–N4)同样非阻断,作者已按 churn 规则延后。
(时序图见英文部分,本轮行为未变,不再重复。)
测试证据 —— 被审 commit 上 PR 自己的 CI
无人值守运行:我未构建或执行任何 PR 代码;下方证据是本轮经 API 重新获取的 93c909cede 上 PR 自己的 CI。全部出结果 —— 无未决检查、无失败。Integration Tests (CLI, No Sandbox) 与 macOS/Windows 单测矩阵为 skipped —— fork PR 密钥门控所致,不是失败;无密钥集成套件已代为运行并通过。作者的本地测试数字(809 bridge / 511 agent / 424 core+hooks)仍是其自述,未在此独立复跑。
(CI 表格见英文部分,机器可读区域标记内为同一份数据。)
核心主张是行为性的,绿色单测本身无法钉住它 —— bridge 测试使用假 channel。能裁决它的两条路径如今都已在该 head 上落地:
- 沙箱
@qwen-code /verify报告 ✅ 通过 —— 可合并(代理结论):对照 base 构建的 A/B、无 mock 的断言、定向门禁。它是给人类评审者的建议性证据 —— 仍是自动化流水线的产物,请作为一个输入而非结论来读。 - @wenshao 在 Linux 上用真实
qwen servedaemon 与真实qwen --acp子进程(三臂:base 对 PR head)独立跑完了完整 Reviewer Test Plan,报告 PR 声称的一切均可复现 —— 超时初始化回收 hook 进程树、迟到的旧子进程被按精确 ID 关闭、清理不确定时只对新鲜准入失败关闭、健康兄弟仍可用。那是维护者的证据,不是我的,也是本线程中最强的信号。他的四条非阻断注记(N1–N4)经作者评估后按 churn 规则延后。
本 PR 的行为主张不再有任何一点仅依赖作者自述。
— Qwen Code · qwen3.8-max
Reviewed at 93c909cede7056c5566b291ef0ad361de5c52a4c · re-run with @qwen-code /triage
|
Confidence: 3/5 — clean review at this head; the 3 is pure policy, not doubt. The Stage 0 core-size escalation (774 production lines across Honest read after five gate rounds: this PR has earned a merge by my assessment, and since round 4 the evidence has caught up with the review. The What is left, stated plainly:
⏸️ Deferring to @wenshao — you have already supplied the human sign-off the policy cap exists to demand (your approval plus your independent live verification), so what remains is mechanical, not judgmental: dismissing this bot's stale request-changes on the superseded heads (if your process allows) to correct the recorded state, and one more maintainer approval to meet 中文说明置信度:3/5 —— 该 head 上审查干净;3 分纯属策略封顶,而非存疑。Stage 0 核心规模升级(774 行生产代码横跨 五轮门禁后的诚实判断:以我的评估,这个 PR 配得上合并,而且自第 4 轮以来证据已经追上了审查。该 head 上的 剩余事项,直说:
⏸️ 转交 @wenshao —— 你已经提供了策略封顶所要求的人工签核(你的批准加上独立的真实验证),因此剩余的是机械事项而非判断事项:(若流程允许)dismiss 本机器人在被取代 head 上的过时 request-changes 以修正记录状态,再加一个维护者批准以满足 — Qwen Code · qwen3.8-max Reviewed at |
🩺 serve daemon A/BBuilt the PR base vs this PR head ✅ No response changes against the PR base across 12 scenario(s). — Qwen Code · serve A/B |
tmux E2E test report (head
|
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 4746 passed · 0 failed · 4746 total Flakiness gate: ✅ 5 changed test file(s) x 5 identical rounds, no divergence 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:4746 通过 · 0 失败 · 4746 总计 抖动门:✅ 5 changed test file(s) x 5 identical rounds, no divergence Verification reportPR 10268 Deep Verification ReportVerdict: 中文摘要
Central claim and A/B proofCentral claim: when a managed ACP Harness:
Head run: 26/26 scripted assertions; base run: 25/25 (base-side cells assert the bug). Empty-channel branch ( Corrections
FindingsNone blocking.
Mutation matrix (vacuity) — zero survivorsAll mutants applied by exact string replacement in scratch trees, run through the same vitest
Hook process-tree reclamation (real processes)
A/A by construction: Targeted gates
Gate liveness: each package's gate was proven live by a red mutant run in the same file Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
中文说明
仅完成部分审查,审查缺口已披露。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.22.2)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Addressed the current review round in e279783.
Verification:
The repository-wide build and CLI typecheck still encounter the known pre-existing Ink selection API/type errors in unchanged UI files; no evidence connects those baseline failures to this branch. Replied to and resolved 16 review threads. |
chiga0
left a comment
There was a problem hiding this comment.
Deep-tier review of the session initialization deadline and late-cleanup compatibility layer. No blocking findings.
CI bot R1-11 (Critical) — REFUTED: The CI bot claimed channelIsCondemned "still recognizes only isQuarantined/restoreSettlementOverdue". Looking at the PR diff, channelIsCondemned is a new function introduced by this PR at bridge.ts:3482–3489, and it correctly includes all four states: isQuarantined, restoreSettlementOverdue, newSessionCleanupFailed, and newSessionSettlementOverdue. The old two-condition inline check at the former lines 757–758 was replaced by the new channelIsCondemned call. Both call sites that the CI bot flagged (closeIfChildUnheld agentCloseTimeoutMs and entryIsAutoCloseCandidate capability carve-out) already use channelIsCondemned in the submitted code. The "probe" findings the CI bot reported appear to reflect a pre-PR baseline, not the current diff.
Core mechanism — verified correct:
freshSessionBlocker()(lines 2646–2662) checks all four condemned states in order, returning the rightBridgeChannelUnavailableReason.newSessionSettlementOverdueis cleared at line 4745 whenci.unsettledAbandonedNewSessions.size === 0, i.e., after the last abandoned session settles. Correct.newSessionCleanupFailedis set and never cleared by design — the channel is condemned until drained and reaped. Correct.channelIsCondemnedconsistently used at all three drain-path call sites (lines 3043, 3151, 3202).
Suggestions (deferred, not blocking):
- R1-9: Load/restore-path admission counters for
abandonedNewSessionSettlements.sizelack test coverage. - R1-14: Child-side-deadline timeouts don't emit the
session.new.public_resulttelemetry event or thedecision=stderr line that the bridge-timer path emits; diagnostic gap. - R1-16: Caller-supplied ID fence during abandoned newSession gives a bare
RestoreInProgressErrorwithout theawaiting_abandoned_cleanupreason or budget-derived retry hint. - R1-1/R1-3/R1-12/R1-13: Documentation overclaims quarantine as "temporary" in contexts where
newSessionCleanupFailedis permanent until channel death.
CI disclosure: build-cli is SKIPPED on this head — no unit test run evidence for any of the concurrency or cancellation changes. web-shell E2E Smoke passes; Desktop Shell, Test, and daemon E2E checks did not run.
Reviewed with AI assistance.
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 4824 passed · 0 failed · 4824 total Flakiness gate: 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:4824 通过 · 0 失败 · 4824 总计 抖动门: Verification reportPR 10268 Deep Verification Report (follow-up round)Verdict: This is a follow-up round: the previous round verified head 中文 — 判定:✅ 通过 · 可合入(agent 判定)本轮为复验轮:上一轮在 head
Previous-finding status (follow-up round)
Central claim and A/B proofCentral claim: when a managed ACP Harness:
Head: 38/38 scripted assertions ×2 runs. Base: 24/24 ×2 runs. Discarded base-arm predictions (reported, not buried) — my first base run had four
Corrections
FindingsNone blocking.
Mutation matrix (vacuity) — 13/13 killed, zero survivorsAll mutants applied by exact string replacement at the new head, run through the package's
Adjudicated probe: the first M-F2 variant targeted the branch-admission cap site Hook process-tree reclamation (real processes, A/A)
A/A by construction: Targeted gates
Gate liveness: proven in the same round before any green result was cited. The mutation Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Not reviewed: reverse audit — reached the 5-round cap still reporting (rounds 3–5 each found new gaps); terminated by cap, not by convergence.
Deferred under the convergence posture (round 2, not a blocker) — recorded, not requested in this round:
packages/acp-bridge/src/bridge.test.ts:12801 — [probe] absolute-deadline contract asserted only as expect.any(Number)packages/acp-bridge/src/bridge.ts:2668 — [probe] per-reason retry-hint ternary has no observing testpackages/acp-bridge/src/bridge.ts:13569 — [review] shutdown await of abandoned new-session settlements is untestedpackages/cli/src/acp-integration/acpAgent.test.ts:2318 — [review] createAndStoreSession's geminiClient.initialize signal is untestedpackages/acp-bridge/src/bridge.ts:13569 — [probe] shutdown settlement snapshot misses in-flight spawns abandoned laterpackages/core/src/core/client.test.ts:1106 — [probe] post-success throwIfAborted() in fireSessionStartHook is untestedpackages/core/src/core/client.test.ts:1121 — [probe] GeminiClient startChat signal seams have no driving testpackages/acp-bridge/src/bridge.test.ts:21406 — [probe] acceptance side of the timer-range boundary is unpinnedpackages/acp-bridge/src/bridge.ts:8972 — [probe] transient capacity double-count between abandonment and inFlightSpawns.delete
中文说明
仅完成部分审查,审查缺口已披露。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
未审查:reverse audit — reached the 5-round cap still reporting (rounds 3–5 each found new gaps); terminated by cap, not by convergence。
收敛姿态下延后(第 2 轮,非阻断)——已记录,本轮不要求修改:共 9 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.2)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Addressed the current Critical review finding in e8c9417.
To honor the review's stated convergence posture and the repository's review-churn rule, this push intentionally contains no Suggestion-only changes. R1-1, R1-6, R2-2 through R2-7, and the review's explicitly disclosed deferred audit gaps remain recorded for follow-up rather than widening this PR further. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
3 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:
- deadline meta contract asserted only as expect.any(Number) (bridge.test.ts:12801) — already reported (round-2 deferred list, review 5043485951)
- per-reason retry-hint ternary has no observing test on the 503 path (bridge.ts:2668) — already reported (round-2 deferred list, review 5043485951)
- createAndStoreSession post-config signal checkpoints untested (acpAgent.test.ts:2318) — already reported (round-2 deferred list, review 5043485951)
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.
Deferred under the convergence posture (round 3, not a blocker) — recorded, not requested in this round:
docs/developers/qwen-serve-protocol.md:2133 — [review] R1-1 settlement-overdue paragraph still says "settles cleanly first" while the shared finally clears on either outcome — still stands, deferred (convergence posture)packages/core/src/config/config.test.ts:4251 — [review] R1-6 post-Gemini signal cancellation checkpoints still lack isolated coverage — still stands, deferred (convergence posture)packages/cli/src/acp-integration/acpAgent.test.ts:2363 — [review] R2-2 timer-range invalid-deadline case still sits exactly 1 ms past the boundary (wall-clock race) — still stands, deferred (convergence posture)packages/acp-bridge/src/bridge.test.ts:13048 — [review] R2-3 new-session settlement telemetry variants still unpinned (late_result polarity, cleanup_result closed/quarantined, settlement_overdue) — still stands, deferred (convergence postur…docs/developers/qwen-serve-protocol.md:2142 — [review] R2-4 settlement-overdue clearing on late FAILURE settlement still has no test — still stands, deferred (convergence posture)packages/acp-bridge/src/bridge.test.ts:13162 — [review] R2-5 capacity guards' abandoned-settlement term still has no branchSession witness — still stands, deferred (convergence posture)packages/acp-bridge/src/bridge.test.ts:13152 — [review] R2-6 still no test abandons two overlapping newSessions on one channel (multi-token overdue guard) — still stands, deferred (convergence posture)packages/acp-bridge/src/bridge.test.ts:12944 — [review] R2-7 requested-id spawn fence still only driven via loadSession, never resumeSession — still stands, deferred (convergence posture)
Convergence: round 3 posted 13 inline comment(s), 13 of them reported for the first time; the previous round posted 9 (8 new). Findings keep coming back to the same files: packages/acp-bridge/src/bridge.test.ts (findings in round 2; 6 more now); packages/acp-bridge/src/bridge.ts (findings in round 2; 3 more now); packages/cli/src/acp-integration/acpAgent.test.ts (findings in round 2; 2 more now), and 1 more file(s). The rate of new findings is not falling. A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. Batching the remaining fixes and verifying them before the next push, or dropping this PR's reviews to --severity-floor critical, keeps the loop from re-deriving the same set. (Observation only — nothing was withheld from this review because of this observation.)
中文说明
仅完成部分审查,审查缺口已披露。
本轮确认的 3 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
未审查:反向审计——在 5 轮的反审轮数上限内未收敛。
收敛姿态下延后(第 3 轮,非阻断)——已记录,本轮不要求修改:共 8 条(原文未翻译,列表见上方英文部分)。
收敛情况:第 3 轮发布了 13 条行内评论,其中 13 条是首次提出;上一轮发布了 9 条(其中 8 条首次提出)。发现反复回到同一批文件:packages/acp-bridge/src/bridge.test.ts(第 2 轮已出过发现,本轮又有 6 条);packages/acp-bridge/src/bridge.ts(第 2 轮已出过发现,本轮又有 3 条);packages/cli/src/acp-integration/acpAgent.test.ts(第 2 轮已出过发现,本轮又有 2 条),另有 1 个文件。新发现的产出速度没有下降。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。把剩余修复攒成一批、验证后再推送,或将本 PR 的评审降到 --severity-floor critical,可以避免循环反复推导同一组发现。(仅为观察——本轮评审未因此扣留任何内容。)
— qwen3.8-max via Qwen Code /review (v0.22.2)
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 4831 passed · 0 failed · 4831 total Flakiness gate: 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:4831 通过 · 0 失败 · 4831 总计 抖动门: Verification reportPR 10268 Deep Verification Report (follow-up round 2)Verdict: This is a follow-up round: the previous round verified head 中文 — 判定:✅ 通过 · 可合入(agent 判定)本轮为复验轮(第二次):上一轮在 head
Previous-finding status (follow-up round)
Central claim and A/B proofCentral claim: when a managed ACP Harness:
Head: 59/59 scripted assertions. Base: 37/37. Discarded base-arm predictions (reported, not buried) — two harness-prediction bugs of my Delta focus: the four tests added since the previous roundbridge.test.ts grew 816 → 820 (+4). The tests covering the settlement-ownership and
M-H2 adjudication (harness error found and corrected): the first-draft M-H2 deleted the Mutation matrix (vacuity) — 13/13 killed, one adjudicated survivor, 3/3 delta killedAll mutants applied by exact string replacement at the new head, run through the package's
Positive control for the survivor: the same vitest invocation shape killed 15 other mutants in Hook process-tree reclamation (real processes, A/A)
A/A by construction: Targeted gates
Gate liveness: the mutation matrix turned suites red in the identical files as the mutants Corrections
FindingsNone blocking.
Flakiness gate5 rounds × 6 changed test files, one file per vitest invocation: 30/30 runs green, Unlike the previous round (4 of 5 rounds fit its 15-minute budget), this round completed all Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
chiga0
left a comment
There was a problem hiding this comment.
Round 3 — new head 23a2637d, independent re-review.
Prior findings: R1 and R2 both dismissed after author updated. This review is fresh against current head.
Scope
Tier: Deep. Changes touch ACP session lifecycle protocol, timer ordering, late-settlement quarantine state machine, and AbortSignal cancellation chain. All 20 changed files were read; cross-file context was fetched for the key contracts.
CI:
| Job | Result |
|---|---|
| Test (ubuntu-latest, Node 22.x) | ✅ pass (34m26s) |
| Test (macos-latest, Node 22.x) | |
| Test (windows-latest, Node 22.x) | |
| Integration Tests (CLI, No Sandbox) | |
| Real daemon E2E / Java 11 | ✅ pass |
Platform-specific timer resolution and path handling are unreviewed dimensions. Author confirms macOS-only manual testing.
What I verified
Contract chain: Bridge sends SESSION_INITIALIZATION_DEADLINE_META_KEY = Date.now() + initTimeoutMs; agent reads it only when isTrustedManagedParent(), validates positive safe integer ≤ 2^31-1, converts to remainingMs = raw - Date.now(), arms AbortController. Forged deadlines from untrusted callers are silently ignored — confirmed by the untrusted-parent test.
Signal propagation: agent.newSession → config.initialize → llmClient.initialize → startChat → fireSessionStartHook → hookSystem.fireSessionStartEvent. Signal passed at each hop. fireSessionStartHook catch block calls signal?.throwIfAborted() before warn+swallow, which surfaces cancellation even when the hook throws independently (tested at client.test.ts:1108).
Session publication order: Abort checkpoint after registerCreateSubSessionTool in createAndStoreSession fires before this.sessions.set, consistent with the comment "BEFORE the session is published." Abort here leaves nothing in the session map; settleAbandonedNewSession(ci, token, undefined, ...) exits early in the finally block cleanly.
Quarantine state machine: channelIsCondemned covers all four states. Used in confirmChildUnheld, closeSessions, and maybeCloseIdleSession — verified by grep.
Session cap accounting: abandonedNewSessionSettlements.size at three cap-check sites. Test at bridge.test.ts:12761 confirms a timed-out spawn counts against maxSessions until abandoned settlement resolves.
initTimeoutMs validation: Tightened to positive integer ≤ 2^31-1. Required for Date.now() + initTimeoutMs arithmetic.
settleAbandonedNewSession loop: spawnOwner && lateSessionId !== requestedSessionId guard correctly waits for an in-flight spawn owning the id, passes through when the late id IS the requested id. Tested by "does not close a late newSession id owned by an in-flight spawn."
_meta now unconditional: Backward-compatible — legacy agents ignore unknown fields.
Cross-check against existing reviews
Confirmed:
bridgeErrors.ts JSDoc ("settlement-overdue states may clear when the abandoned request settles") — For late successes, the state actually clears in settleAbandonedNewSession's finally block only after the sessionClose call completes, not at raw request settlement. "When the abandoned request settles" understates this for the success path. The protocol doc 503-entry is precise ("after a late success completes its exact-ID cleanup"); this JSDoc should match.
docs/developers/qwen-serve-protocol.md POST /session section — mentions "init timeout" in prose at the coalescing note, but has no formal 504 init_timeout error entry, even though error-response.ts now returns 504 / init_timeout / retryable:true / Retry-After for BridgeTimeoutError. The error contract and Retry-After semantics for timed-out session creation are not discoverable from the spec.
Cannot rule:
R2-1 round-3 fix-induced finding — I traced the Retry-After plumbing through error-response.ts and dispatch.ts and do not see an obvious contradiction at head, but the original R2-1 inline comment is not visible to me. Recording as a miss I cannot rule on.
My own findings
None beyond the two confirmed above (documentation precision).
Reviewed with AI assistance.
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
|
Round 3 documentation follow-up for 23a2637
No correctness, security, data-loss, or regression defect was identified, so this review round does not change the branch. |
wenshao
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
Not reviewed: reverse-audit chunk 5 round 4 — auditor failed twice; round 5 returned a substantive dry receipt.
Not reviewed: reverse-audit chunk 7 round 3 — receipt wording did not satisfy retirement certification; rounds 4 and 5 returned substantive dry receipts.
Not reviewed: "agent verify (round 2)" — pointed at diff lines it never opened: it made tool calls, but none of them read the diff.
Deferred under the convergence posture (round 6, not a blocker) — recorded, not requested in this round:
docs/developers/qwen-serve-protocol.md:2175 — [review] The recovery contract omits the id_reclaimed path that skips exact-ID cleanupintegration-tests:1 — [review] The linked shared-channel slow-hook incident has no committed end-to-end replaypackages/acp-bridge/src/bridge.test.ts:12800 — [probe] The deadline metadata test accepts any numeric valuepackages/acp-bridge/src/bridge.test.ts:13332 — [review] The per-request overdue-state test never makes both requests overdue simultaneouslypackages/acp-bridge/src/bridge.test.ts:13347 — [review] Capacity tests do not cover pending abandonment when spare capacity remainspackages/acp-bridge/src/bridge.ts:13612 — [review] Shutdown waiting for abandoned newSession settlements is not regression-testedpackages/acp-bridge/src/bridgeErrors.ts:638 — [review] BridgeChannelQuarantinedError JSDoc understates late-success cleanup requirementspackages/cli/src/acp-integration/acpAgent.test.ts:2314 — [review] Agent tests do not pin checkpoints after late-resolving non-cancellable phasespackages/cli/src/acp-integration/acpAgent.test.ts:2362 — [review] The maximum-deadline boundary test has only millisecond-scale race slackpackages/cli/src/serve/server/error-response.test.ts:77 — [review] The REST route does not exercise BridgeTimeoutError mapping end to endpackages/core/src/config/config.test.ts:4377 — [review] Config tests do not isolate checkpoints after late-resolving initialization phasespackages/core/src/core/client.ts:520 — [review] Restore branches do not have focused tests for AbortSignal forwarding
Convergence: round 6 posted 1 inline comment(s), 1 of them reported for the first time. Findings keep coming back to the same files: packages/cli/src/serve/server/error-response.ts (findings in round 5; 1 more now). (Evidence: the previous round was recovered from a marker this account did not post and merged over this account's own entries, so some of those rounds may not be this account's own.) A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. (Observation only — nothing was withheld from this review because of this observation.)
Mechanism health: this round did not close cleanly, so it withholds the incremental anchor — and the round it recovered had no anchor this round could use either — none at all, one with no certifier, one certified by an identity other than the one this round runs under, or one this round's fetch refused or resolved to the head — so the next review re-reads the whole diff unless recovery grafts an earlier own anchor that the round running it can use onto the complete work list this round leaves behind, and keeps doing so until a round's marker carries an anchor again or a graft lands that the round running it can use. (Stated, not acted on — this changes nothing about what the round posts.)
[Critical] R6-2 [certifies-falsely] [new-surface] Abandoned restore cleanup accepts a close refusal as successful cleanup at packages/acp-bridge/src/bridge.ts:7488. A timed-out restore that later succeeds can receive {closed:false} from sessionClose; the restore path ignores that response, records cleanup as closed, clears the fence, and reopens admission while the late Session may remain alive. Validate closed === true exactly as the abandoned newSession cleanup path does. Existing sibling sessions must remain usable during quarantine and channel drain, as documented in docs/developers/qwen-serve-protocol.md:2175. Add a bridge test where late restore cleanup returns closed:false; removing the validation must make the test fail. Witness: not run — the fulfilled-response path deterministically never inspects closed.
[Critical] packages/core/src/hooks/instructionsLoadedCallback.ts:29 — [review] InstructionsLoaded hooks do not receive the initialization deadline signal (relocated from the deferral channel — a Critical is never deferred, it posts)
[Critical] packages/acp-bridge/src/bridge.ts:7569 — [probe] Restore settlement-overdue remains set after the only overdue restore settles (relocated from the deferral channel — a Critical is never deferred, it posts)
中文说明
仅完成部分审查,审查缺口已披露。
未审查:reverse-audit chunk 5 round 4 — auditor failed twice; round 5 returned a substantive dry receipt。
未审查:reverse-audit chunk 7 round 3 — receipt wording did not satisfy retirement certification; rounds 4 and 5 returned substantive dry receipts。
未审查:"agent verify (round 2)"——启动 prompt 为它指定了 diff 中的行,但它从未打开:有工具调用,却没有一次读取 diff。
收敛姿态下延后(第 6 轮,非阻断)——已记录,本轮不要求修改:共 12 条(原文未翻译,列表见上方英文部分)。
收敛情况:第 6 轮发布了 1 条行内评论,其中 1 条是首次提出。发现反复回到同一批文件:packages/cli/src/serve/server/error-response.ts(第 5 轮已出过发现,本轮又有 1 条)。(证据说明:上一轮的数据来自并非本账号发布的标记,并与本账号自己的条目合并,上述轮次中的部分可能不属于本账号。)一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。(仅为观察——本轮评审未因此扣留任何内容。)
机制健康:本轮未能干净收尾,因而扣留了增量锚点,而它恢复到的那一轮也没有留下本轮可用的锚点——要么完全没有、要么没有认证者、要么由本轮运行身份之外的身份认证、要么被本轮的获取拒绝或解析为头提交——因此下一次评审将重读整个 diff,除非恢复流程把本轮能使用的更早自有锚点嫁接到本轮留下的完整工作清单上;并会一直如此,直到某一轮的标记重新带上锚点,或落地的嫁接能被运行该轮的评审使用。(仅陈述,不据此行动——这不改变本轮发布的任何内容。)
[Critical] R6-2 [certifies-falsely] [new-surface] Abandoned restore cleanup accepts a close refusal as successful cleanup at packages/acp-bridge/src/bridge.ts:7488. A timed-out restore that later succeeds can receive {closed:false} from sessionClose; the restore path ignores that response, records cleanup as closed, clears the fence, and reopens admission while the late Session may remain alive. Validate closed === true exactly as the abandoned newSession cleanup path does. Existing sibling sessions must remain usable during quarantine and channel drain, as documented in docs/developers/qwen-serve-protocol.md:2175. Add a bridge test where late restore cleanup returns closed:false; removing the validation must make the test fail. Witness: not run — the fulfilled-response path deterministically never inspects closed.
[Critical] packages/core/src/hooks/instructionsLoadedCallback.ts:29 — [review] InstructionsLoaded hooks do not receive the initialization deadline signal (relocated from the deferral channel — a Critical is never deferred, it posts)
[Critical] packages/acp-bridge/src/bridge.ts:7569 — [probe] Restore settlement-overdue remains set after the only overdue restore settles (relocated from the deferral channel — a Critical is never deferred, it posts)
— gpt-5.6-sol@954e5164 via Qwen Code /review (v0.22.2)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
Addressed all four round-6 Critical findings in 93c909c.
Verification: CLI mapper tests 46/46, ACP Bridge 822/822, Core Config and callback 594/594, HookRunner cancellation checks 3/3, relevant ESLint, Prettier, diff checks, and ACP Bridge/Core typechecks passed. The repository-wide build/typecheck remains blocked only by the known unchanged Ink selection API/type mismatch in CLI UI code; no changed-file diagnostic was emitted. One inline thread was replied to and is being resolved. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
6 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:
- staggered overdue test never has both abandoned newSessions overdue simultaneously — already reported (comment 3878640381, R4-2), author deferred
- timer-range 'beyond the timer range' test has only 1ms of wall-clock slack — already reported (comment 3873973798 R2-2 and comment 3875658122 R3-14), author deferred
- createAndStoreSession pre-publication signal checkpoints untested — already reported (round-2 deferred list, review 5043485951; comment 3875658117)
- deadline meta contract asserted only as expect.any(Number) — already reported (round-2 deferred list, review 5043485951; comment 3875658109)
- initializeTimeoutMs accept-side boundary (2^31-1) untested — already reported (round-2 deferred list, review 5043485951, bridge.test.ts:21406)
- client-level initialize/startChat signal seams have no driving test — already reported (round-2 deferred list, review 5043485951, client.test.ts:1121)
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) did not pass in CI and its suite did not run locally.
Deferred under the convergence posture (round 7, not a blocker) — recorded, not requested in this round:
packages/core/src/core/client.ts:1995 — [probe] duplicated fireSessionStartEvent ternarypackages/acp-bridge/src/bridge.ts:2634 — [review] stale 'Two independent conditions' comment above freshSessionBlockerpackages/acp-bridge/src/bridge.test.ts:10980 — [probe] restore-family late-failure overdue clearing is unpinnedpackages/acp-bridge/src/bridge.ts:4633 — [probe] misleading decision= breadcrumb on the child-enforced-deadline pathpackages/core/src/hooks/instructionsLoadedCallback.ts:38 — [probe] R6-3 (fix-induced): InstructionsLoaded signal cannot surface cancellationpackages/cli/src/serve/server/error-response.ts:217 — [review] R5-1 still stands: init_timeout/504 contract pinned only at the mapper unit level — no route-level test
中文说明
仅完成部分审查,审查缺口已披露。
本轮确认的 6 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) did not pass in CI and its suite did not run locally。
收敛姿态下延后(第 7 轮,非阻断)——已记录,本轮不要求修改:共 6 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.2)
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 7584 passed · 0 failed · 7584 total Flakiness gate: 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:7584 通过 · 0 失败 · 7584 总计 抖动门: Verification reportPR 10268 Deep Verification Report (follow-up round 3)Verdict: 中文 — 判定:✅ 通过 · 可合入(agent 判定)本轮为复验轮(第三次):上一轮在 head
Previous-finding status (follow-up round)
Delta reconstruction (what changed since round 2)The round-2 head
Central claim and A/B proofCentral claim: when a managed ACP Harness:
Head: 51/51 scripted checks per run. Base: 51/51 per run. Discarded base-arm predictions (reported, not buried) — two harness-prediction bugs of my Mutation matrix (vacuity) — 22/23 killed, one adjudicated survivorAll mutants applied by exact string replacement with occurrence-count verification at the new
Positive controls: 19 green unmutated filter-control runs in the identical vitest invocation Hook process-tree reclamation (real processes, A/A)
The tree-reclamation machinery itself is base's and untouched by this PR; the PR's contribution Targeted gates
Gate liveness: the mutation matrix turned suites red in the identical files as the mutants Corrections
FindingsNone blocking. None new.
Flakiness gate3 rounds × 8 changed test files (the 7 of round 2 plus Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
Local verification report — real daemon, three armsI built a real verification environment for this PR on Linux and ran the full Reviewer Test Plan end to end against a live Harness
Environment: Linux 6.12 x86_64, Node 22.22.2, Chromium-rendered evidence cards. Bundles built per arm with 1. The bug reproduces on BASE and is fixed on AFTERThe BASE column is exactly #10266: an opaque On AFTER: 2. Mixed-version (old child ignores the private deadline)Every stage of the compatibility lifecycle fired, in order, over real HTTP:
Daemon stderr also carries 3. ACP wire captureAll 6 4. RED/GREEN, trust boundary, gates
Claim-by-claim against your Reviewer Test Plan
Non-blocking notesN1 — the new late-lifecycle telemetry events never reach the exporter. With N2 — the child-side error-mapping branch appears unreachable for the timeout path. The design doc says the child reports N3 — the "Tested on" table can be updated. Linux is now exercised: this run covers the full plan on Linux, including the built-daemon E2E your description lists as out of scope. The full-build blocker you hit is avoidable — N4 — cosmetic. The new (much longer) Verdict: looks good to me — the behaviour matches the design doc on every claim I could drive, including the compatibility lifecycle and the trust boundary. None of N1–N4 blocks the merge. 中文版本本地验证报告 —— 真实 daemon,三条臂我在 Linux 上为本 PR 搭建了真实验证环境,用运行中的 验证环境
环境:Linux 6.12 x86_64、Node 22.22.2;证据图用 Chromium 渲染。每条臂用 1. BASE 复现 bug,AFTER 修复BASE 一列正是 #10266:不透明的 AFTER: 2. 混合版本(旧子进程忽略私有 deadline)兼容生命周期的每个阶段都在真实 HTTP 上按序触发:
daemon stderr 里还有 3. ACP 线级抓包全部 6 次 4. RED/GREEN、信任边界、门禁
逐条对照你的 Reviewer Test Plan
非阻塞说明N1 —— 新增的迟到期 telemetry 事件没能进入 exporter。 打开 N2 —— 子进程侧的错误映射分支在超时路径上似乎不可达。 设计文档写的是:子进程报告 N3 —— "Tested on" 表格可以更新了。 Linux 现已覆盖:本次在 Linux 上跑通了完整测试计划,包括你在描述里列为范围外的 built-daemon E2E。你遇到的全量构建阻塞其实可以绕过 —— N4 —— 纯观感。 结论:我认为可以合入 —— 凡是我能驱动的声称,行为都与设计文档一致,包括兼容生命周期和信任边界。N1–N4 均不阻塞合并。 🤖 Generated with Claude Code — Claude Opus 5 (1M context) |
|
Thanks for the thorough three-arm verification. We reviewed N1–N4 against head |
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 7988 passed · 0 failed · 7988 total Flakiness gate: 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:7988 通过 · 0 失败 · 7988 总计 抖动门: Verification reportPR 10268 Deep Verification Report (follow-up round 4)Verdict: 中文 — 判定:✅ 通过 · 可合入(agent 判定)本轮为复验轮(第四次):PR head 与上一轮完全相同(
Previous-finding status (follow-up round)
Delta reconstruction (what changed since round 3)The PR head is unchanged (
Merge integrity at the combined files: PR mechanism-marker counts are identical Central claim and A/B proofCentral claim: when a managed ACP Harness:
Head: 74/74 scripted checks per run. Base: 55/55 per run Discarded base-arm predictions (reported, not buried) — three harness-prediction bugs Mutation matrix (vacuity) — 12/13 killed, one adjudicated survivorAll mutants applied by exact string replacement with occurrence-count verification at the
Mutants round 3 ran that this round did not re-run (M-C, M-D, M-CD combination, M-F1/F2, Targeted gates (merged tree)
Gate liveness: the mutation matrix turned suites red in the identical files as the mutants Corrections
FindingsNone blocking. None new.
Flakiness samplingNo dedicated multi-round flakiness soak this round (round 3 ran 24 green runs across the 8 Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
yiliang114
left a comment
There was a problem hiding this comment.
Re-approving after the new head 93c909c: re-verified the overdue-token Set (bridge.ts) replacing the channel-wide boolean, the doc alignments (late-failure vs late-success clearing, fence-table timeout wording), and the test pins; all 53 threads resolved and CI fully green on the exact head (0 failures, 0 pending).
Already have 2 approves,3ks.
yiliang114
left a comment
There was a problem hiding this comment.
Approving after re-verification at head 93c909c: the overdue-token Set design holds (per-token add/delete, admission reads size>0), doc semantics aligned, all 53 threads resolved, CI fully green on the exact head (0 failures, 0 pending). Re-approval on the refreshed head.

























What this PR does
This PR makes the existing daemon session initialization budget authoritative end to end. The bridge sends a private absolute deadline with each managed ACP new-session request, the child propagates cancellation through configuration, Gemini startup, and
SessionStarthooks, and a timed-out Session is rejected before publication. For older children that ignore the deadline, the bridge tracks the late request, closes any late-created Session by exact ID, retains admission and caller-supplied ID fences until cleanup settles, and quarantines only fresh session creation when cleanup remains uncertain. Healthy sibling Sessions on a shared channel remain usable.Why it's needed
The public
newSessiontimeout previously rejected only the bridge wrapper while the underlying child work could continue. A slowSessionStartcommand hook could therefore finish after the caller receivedinit_timeout, leave descendant processes running, and publish a real child Session that the bridge never registered. Killing the shared ACP channel at the first timeout would avoid hidden work but would also terminate unrelated healthy Sessions, so the timeout needs request-scoped cancellation plus a bounded compatibility lifecycle for older children.Reviewer Test Plan
How to verify
On a managed shared ACP channel, keep one healthy Session alive and create a second Session whose
SessionStartcommand hook exceeds the initialization budget. Expect the second request to fail with the existinginit_timeoutcontract, never publish a Session, and reclaim both the hook root and descendant, while the healthy sibling still completes a prompt. With a compatibility child that ignores the private deadline, resolvenewSessionafter the public timeout and confirm the bridge sends exactly one close request for the returned Session ID. Make the close returnclosed: false, and separately leave the raw request unsettled for one further budget; in both cases expect fresh admission to fail with the documentedacp_channel_unavailablereason while the sibling remains usable.Evidence (Before & After)
Before: the caller received
init_timeout, but an older or non-cancelling child could finish initialization later, publish an unregistered Session, and leave aSessionStarthook process tree running.After: managed children abort before Session publication and tree-aware Hook cancellation reclaims the root and descendant. Older children are contained by exact-ID late cleanup; uncertain cleanup fails closed only for fresh admission and does not terminate healthy siblings.
Tested on
Environment (optional)
macOS 26.4.1 (Darwin 25.4.0 arm64), Node.js 22.22.3, npm 10.9.8. The full ACP Bridge test file passed 809 tests, the ACP Agent test file passed 511 tests, and the Core client plus HookRunner files passed 424 tests. The affected ACP Bridge and Core packages passed build and typecheck; changed files passed ESLint, Prettier, and
git diff --check. A real HookRunner process-tree harness confirmed that an abort reaped both the hook root and a descendant that ignored SIGTERM. The repository-widenpm run build && npm run bundleremains blocked before bundling by the current main branch's unrelated Ink selection API/type mismatch in CLI UI files.Risk & Scope
init_timeout; the private deadline is restricted to the trusted managed-parent path. Two additiveacp_channel_unavailablereason values are documented for clients that inspect quarantine details.Linked Issues
Closes #10266
中文说明
本 PR 做了什么
本 PR 让现有 daemon Session 初始化预算在整条链路上具备权威性。Bridge 会在每个受管 ACP 新建 Session 请求中发送私有的绝对 deadline,子进程将取消信号传递到配置初始化、Gemini 启动和
SessionStartHook,并在发布前拒绝已经超时的 Session。对于忽略 deadline 的旧子进程,Bridge 会跟踪迟到请求,按精确 Session ID 关闭迟到创建的 Session,在清理完成前保留准入和调用方指定 ID 的 fence,并在无法确认清理结果时只隔离新的 Session 创建。共享 channel 上的健康兄弟 Session 仍然可用。为什么需要
此前公开的
newSession超时只会拒绝 Bridge 包装层,底层子进程工作仍可能继续。缓慢的SessionStart命令 Hook 可能在调用方已经收到init_timeout后才完成,留下仍在运行的后代进程,并发布一个 Bridge 从未注册的真实子 Session。首次超时时直接终止共享 ACP channel 虽然可以避免隐藏任务,但也会终止无关的健康 Session,因此这里需要请求级取消,以及面向旧子进程的有界兼容生命周期。Reviewer 测试计划
如何验证
在受管共享 ACP channel 上保留一个健康 Session,并创建第二个 Session,使它的
SessionStart命令 Hook 超过初始化预算。预期第二个请求以现有init_timeout契约失败、始终不发布 Session,并回收 Hook 根进程和后代进程,同时健康兄弟仍可完成一次 prompt。再使用忽略私有 deadline 的兼容子进程,在公开超时后让newSession返回,并确认 Bridge 仅针对返回的 Session ID 发送一次精确 close 请求。让 close 返回closed: false,并单独让原始请求再经过一个完整预算仍不 settle;两种情况下都应看到新准入以文档化的acp_channel_unavailablereason 失败,而兄弟 Session 仍然可用。证据(前后对比)
改动前:调用方会收到
init_timeout,但旧版或无法取消的子进程仍可能稍后完成初始化,发布一个未注册的 Session,并留下仍在运行的SessionStartHook 进程树。改动后:受管子进程会在 Session 发布前中止,具备进程树感知能力的 Hook 取消会回收根进程和后代。旧子进程通过精确 ID 的迟到清理进行约束;清理结果不确定时只对新准入失败关闭,不会终止健康兄弟。
测试平台
环境(可选)
macOS 26.4.1(Darwin 25.4.0 arm64)、Node.js 22.22.3、npm 10.9.8。完整 ACP Bridge 测试文件通过 809 个测试,ACP Agent 测试文件通过 511 个测试,Core client 与 HookRunner 文件通过 424 个测试。受影响的 ACP Bridge 和 Core 包通过 build 与 typecheck;改动文件通过 ESLint、Prettier 和
git diff --check。真实 HookRunner 进程树测试确认 abort 会回收 Hook 根进程,以及一个忽略 SIGTERM 的后代进程。全仓库npm run build && npm run bundle仍在 bundle 前被当前 main 分支中与本改动无关的 CLI UI Ink selection API/类型不匹配阻断。风险与范围
init_timeout;私有 deadline 仅限可信受管父进程路径。针对检查隔离细节的客户端,文档新增了两个附加的acp_channel_unavailablereason 值。关联 Issue
Closes #10266